Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit 632f70e865726a3ce9674604869c98369ccda4fe


Parents : 533a10a
Author : Ivan <ivan@quad4.io>
Signature : Invalid signer <e46112d44649266d71fe2193e00a4710>, author is <ivan@quad4.io>
Date : 2026-06-29T07:25:53-05:00

feat(tests): update backend tests with new server bind status schema and improve identity mock for interface stats tests

Changes
Diff

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index df08a855..6ceaccf2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -116,7 +116,8 @@ jobs:
pnpm exec vitest run --config vitest.electron.config.js
;;
backend-tests)
- MESHCHAT_SKIP_STORAGE_LOCK=1 uv run python -m pytest tests/backend -n auto \
+ MESHCHAT_SKIP_STORAGE_LOCK=1 COVERAGE_FILE="${{ runner.temp }}/.coverage" \
+ uv run python -m pytest tests/backend -n auto \
--cov=meshchatx/src/backend
;;
lang-tests)

diff --git a/meshchatx/src/backend/database/__init__.py b/meshchatx/src/backend/database/__init__.py
index 9cbe20d1..501e14f0 100644
--- a/meshchatx/src/backend/database/__init__.py
+++ b/meshchatx/src/backend/database/__init__.py
@@ -398,8 +398,11 @@ class Database:
self,
zf: zipfile.ZipFile,
db_basenames: set[str],
+ *,
+ exclude_paths: set[str] | None = None,
) -> list[str]:
identity_dir = self._identity_storage_dir()
+ excluded = {os.path.abspath(path) for path in (exclude_paths or ())}
included: list[str] = []
for root, dirs, files in os.walk(identity_dir):
dirs[:] = [d for d in dirs if d not in BACKUP_SKIP_DIR_NAMES]
@@ -407,6 +410,8 @@ class Database:
if name in db_basenames or name == BACKUP_MANIFEST_NAME:
continue
full_path = os.path.join(root, name)
+ if os.path.abspath(full_path) in excluded:
+ continue
rel_path = os.path.relpath(full_path, identity_dir).replace("\\", "/")
if rel_path.startswith(".."):
continue
@@ -433,13 +438,18 @@ class Database:
main_filename = os.path.basename(paths["main"])
db_basenames = {os.path.basename(p) for p in paths.values()}
+ backup_abs = os.path.abspath(backup_path)
with zipfile.ZipFile(backup_path, "w", compression=zipfile.ZIP_DEFLATED) as zf:
zf.write(paths["main"], arcname=main_filename)
if os.path.exists(paths["wal"]):
zf.write(paths["wal"], arcname=f"{main_filename}-wal")
if os.path.exists(paths["shm"]):
zf.write(paths["shm"], arcname=f"{main_filename}-shm")
- included = self._add_identity_storage_to_zip(zf, db_basenames)
+ included = self._add_identity_storage_to_zip(
+ zf,
+ db_basenames,
+ exclude_paths={backup_abs},
+ )
manifest = {
"version": 1,
"created_at": datetime.now(UTC).isoformat(),

diff --git a/tests/backend/api_json_contract_schemas.py b/tests/backend/api_json_contract_schemas.py
index 1e000cce..d8e0d9a4 100644
--- a/tests/backend/api_json_contract_schemas.py
+++ b/tests/backend/api_json_contract_schemas.py
@@ -159,10 +159,25 @@ APP_INFO_BODY_SCHEMA: dict = {
"additionalProperties": True,
}
+_SERVER_BIND_STATUS_SCHEMA: dict = {
+ "listen_host": {"type": ["string", "null"]},
+ "listen_port": {"type": ["integer", "null"]},
+ "https_enabled": {"type": "boolean"},
+ "is_loopback_bind": {"type": "boolean"},
+ "landlock_kernel_supported": {"type": "boolean"},
+ "landlock_requested": {"type": "boolean"},
+ "landlock_auto_enabled": {"type": "boolean"},
+ "landlock_disabled_by_env": {"type": "boolean"},
+ "landlock_active": {"type": "boolean"},
+}
+
API_V1_STATUS_SCHEMA: dict = {
"type": "object",
"required": ["status"],
- "properties": {"status": {"type": "string", "const": "ok"}},
+ "properties": {
+ "status": {"type": "string", "const": "ok"},
+ **_SERVER_BIND_STATUS_SCHEMA,
+ },
"additionalProperties": False,
}

diff --git a/tests/backend/test_interface_stats_endpoint.py b/tests/backend/test_interface_stats_endpoint.py
index a21968f2..6965f096 100644
--- a/tests/backend/test_interface_stats_endpoint.py
+++ b/tests/backend/test_interface_stats_endpoint.py
@@ -18,21 +18,32 @@ def temp_dir():
@pytest.fixture
-def mock_identity():
- mock_id = MagicMock()
- mock_id.hash = b"test_hash_32_bytes_long_01234567"
- mock_id.hexhash = mock_id.hash.hex()
- mock_id.get_private_key.return_value = b"test_private_key"
- return mock_id
+def mock_rns_minimal():
+ with (
+ patch("RNS.Reticulum") as mock_rns,
+ patch("RNS.Transport"),
+ patch("LXMF.LXMRouter"),
+ patch("meshchatx.meshchat.get_file_path", return_value="/tmp/mock_path"),
+ ):
+ mock_rns_instance = mock_rns.return_value
+ mock_rns_instance.configpath = "/tmp/mock_config"
+ mock_rns_instance.is_connected_to_shared_instance = False
+ mock_rns_instance.transport_enabled.return_value = True
+
+ mock_id = MagicMock()
+ mock_id.hash = b"test_hash_32_bytes_long_01234567"
+ mock_id.hexhash = mock_id.hash.hex()
+ mock_id.get_private_key.return_value = b"test_private_key"
+ yield mock_id
@pytest.mark.asyncio
async def test_interface_stats_serializes_bytes_and_parent_hash_null(
- mock_identity, temp_dir
+ mock_rns_minimal, temp_dir
):
with patch("meshchatx.meshchat.generate_ssl_certificate"):
app_instance = ReticulumMeshChat(
- identity=mock_identity,
+ identity=mock_rns_minimal,
storage_dir=temp_dir,
reticulum_config_dir=temp_dir,
)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────